Azure AD B2C の API コネクタを使ってユーザー作成時にカスタム属性を自動設定してみた
いわさです。
最近 Azure AD B2C のカスタマイズを試行錯誤しているところでして、先日はとりあえずカスタム属性の追加を行ってユーザーフローから登録を行えるところまで確認してみました。
ここで追加した情報はテナント ID とカスタムロールを想定した情報となり、通常は SaaS のオンボーディング時にユーザーが個別で登録するのではなく、何らかの自動でのマッピングや管理者操作による設定が期待される部分だと思います。
Azure AD B2C ではユーザーフローでもカスタムポリシーでも、API コネクタという機能を使ってカスタム処理を実行することが出来ます。
Amazon Cognito に慣れている方向けに言うとカスタムトリガーと同じ概念の機能です。
今回は実際に API コネクタを作成し、カスタム処理を実行することでカスタム属性の値を上書きするところを実施してみましたので紹介したいと思います。
API コネクタを作成
API コネクタの作成手順は次のドキュメントに記載されており、こちらを参考に進めています。
今回はユーザーフローを使っており、ユーザーフローから呼び出される API コネクタをまずは登録する必要があるのですが、HTTP API として用意する必要があります。
稼働環境では Basic 認証あるいはクライアント証明書を使って保護された API を呼び出す必要があるのですが、今回は Azure Functions で保護されていない API を用意して、そのまま実行出来るかを確認することにしました。
API コネクタの登録には HTTP エンドポイントの URL が必要なので、適当な関数を用意して URL を取得します。
AAD B2C テナントの API コネクタメニューで新しい API コネクタを作成します。
テナントあたり最大 20 件までの API コネクタを作成することが出来ます。
以下では Basic 認証のユーザー名とパスワードを入力していますが、実際には関数は保護されていないので適当なユーザー名とパスワードを入力しています。
API コネクタが作成出来たらユーザーフローの API コネクタメニューでどの手順でどのコネクタを呼び出すのかを選択します。
以下の 3 つから選択が可能です。
- サインアップ時に ID プロバイダーとのフェデレーションを行った後
- ユーザーを作成する前
- トークンを送信する前
今回はサインアップ処理の途中でユーザーが作成される直前にカスタム処理を実行したいと思います。
ユーザー作成を中断させる
先程の公式ドキュメントに記述されているのですが、エンドポイントは API コネクタへ適切な形式でレスポンスを行うことでユーザー作成処理に介入することが出来ます。
ひとつはユーザー作成処理を続行するか、中断するか指示することが出来ます。
例えば入力された情報のカスタムチェックを行い、不正な情報だと判断した場合に中断させます。
エンドポイントは API コネクタに対してapplication/json
形式でのレスポンスが必要で、レスポンスボディにはversion
とaction
が必須です。レスポンスが JSON として不正な形式だった場合もユーザーフロー中にエラーが発生します。
ContentType
が違う場合でもうまくいかないので注意してください。
ユーザー作成を中断させる場合は次のようにaction
へShowBlockPage
を設定します。
userMessage
にエラーメッセージを設定することで遷移したエラー画面でメッセージ表示することが出来ます。
#r "Newtonsoft.Json" using System.Net; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Primitives; using Newtonsoft.Json; public static async Task<IActionResult> Run(HttpRequest req, ILogger log) { string hogeresponse = "{\"version\": \"1.0.0\", \"action\": \"ShowBlockPage\", \"userMessage\": \"HogeError\"}"; return new ContentResult(){Content = hogeresponse, ContentType = "application/json"}; }
サインアップ画面でユーザー作成を行います。
このあと API コネクタが実行され、サインアップ処理は中断指示を受け取り、次のような画面へ遷移します。
「HogeError」は関数側で設定したカスタムエラーメッセージですね。
ユーザー作成を続行し、カスタム属性を上書きする
次は中断せずに処理を続行させ、さらに当初の目的だったカスタム属性の設定を行ってみたいと思います。
後述しますが、ユーザー属性にカスタム属性を追加しています。
ユーザー入力はさせたくないのですが、デフォルトで用意されたサインアップユーザーフローだと、ユーザー属性に設定されていないと API コネクタで上書きが出来ないので今回はこのようにしています。
続行&属性上書きを行う場合は次のような関数になりました。
action
にはContinue
を設定し、属性に対して上書きしたい値を設定しています。
ついでに今回はリクエストボディをログ出力してみました。
#r "Newtonsoft.Json" using System.Net; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Primitives; using Newtonsoft.Json; public static async Task<IActionResult> Run(HttpRequest req, ILogger log) { string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); log.LogInformation(requestBody); string hogeresponse = "{\"version\": \"1.0.0\", \"action\": \"Continue\", \"extension_tenant_id\": \"hogetenant1\", \"extension_tenant_user_role\": \"hogerole\"}"; return new ContentResult(){Content = hogeresponse, ContentType = "application/json"}; }
ユーザー作成すると登録に成功し、トークンが返却されました。
jwt.ms で確認してみましょう。
おっ、カスタム属性が Azure Functions で設定した内容で更新されていますね!
良い感じです。
ちなみにリクエストボディの内容は次のような感じでした。
入力内容をチェックしたり、その情報とコントロールプレーンで用意したテナント管理 API とかを組み合わせてドメインからテナント ID 引っ張ってくるとか、色々出来そうですね。
{ "step": "PostAttributeCollection", "client_id": "e6d6fce2-b1bf-434e-83db-8e6be9b1295b", "extension_7e6b17fb881b4363b4c13c3413683460_tenant_id": "111", "extension_7e6b17fb881b4363b4c13c3413683460_tenant_user_role": "222", "ui_locales": "ja", "city": "Sapporo", "country": "日本", "email": "[email protected]", "surname": "iwasa", "givenName": "hoge", "identities": [ { "signInType": "emailAddress", "issuer": "hoge1227org.onmicrosoft.com", "issuerAssignedId": "[email protected]" } ] }
ユーザーフローだとユーザー属性に存在していない情報の更新は出来なかった
今回はユーザーフローでユーザー属性にカスタム属性を追加していたのでサインアップフォームにテナント ID などが表示されてしまいました。
本来であれば次のようにフォームには表示したくないところです。
そのためこのようにして試してみました。
しかし、この場合は次のように収集される属性として扱われないようで、API コネクタ経由で値の設定が出来ませんでした。
おそらくですがユーザー属性に指定した上で、カスタムポリシーでサインアップエクスペリエンスをカスタマイズする必要があるのではないのかなと思っています。
次回はそのあたりもやってみようかな。
さいごに
本日は Azure AD B2C の API コネクタを使ってユーザー作成時にカスタム属性を自動設定してみました。
API コネクタ自体は期待どおり動いてくれましたね。
最初は関数でうまく API コネクタが期待するレスポンスを生成することが出来なくて失敗していたのですが、Content-Type
がうまく設定できていなかったというオチでした。
API コネクタ自体はうまく動いてくれたのですが、カスタムポリシーでサインアップ周りをカスタマイズする必要がありそうなのでこのあたりもやってみます。